from microdot import Microdot, Response, send_file, Request
from LX225BusServo_mi import LX225BusServo as BusServo
import json
import utime as time
from machine import Pin, UART, freq
import network
import re
import os

# 设置CPU频率（ESP32支持）
try:
    freq(240000000)  # 根据实际芯片调整s3-240000000 c3-160000000
except:
    freq(160000000)

# 硬件资源配置
UART_TX = 7  # 根据实际接线修改
UART_RX = 8
UART_PORT = 1

global servo_controller, action_sequence, current_positions, servo_modes  # 全局变量声明
# 全局变量初始化
uart = UART(UART_PORT, baudrate=115200, tx=UART_TX, rx=UART_RX, timeout=1)
servo_controller = BusServo(uart)
action_sequence = []
current_positions = {}
servo_modes = {}

with open('index.html', 'r') as f:
    html = f.read()
# WiFi配置（优先使用STA模式）
WIFI_SSID = "XM_13_Pro"
WIFI_PASS = "12345678"
AP_FALLBACK = True  # 是否启用AP回退模式
AP_SSID = "ServoCtrl"
AP_PASS = "12345678"

def network_init():
    sta = network.WLAN(network.STA_IF)
    sta.active(True)
    
    if not sta.isconnected():
        print(f'Connecting to {WIFI_SSID}...')
        sta.connect(WIFI_SSID, WIFI_PASS)
        for _ in range(20):  # 约10秒超时
            if sta.isconnected():
                break
            time.sleep(0.5)
    
    if not sta.isconnected() and AP_FALLBACK:
        ap = network.WLAN(network.AP_IF)
        ap.active(True)
        ap.config(essid=AP_SSID, password=AP_PASS)
        print(f'AP mode: {ap.ifconfig()[0]}')
    else:
        print(f'STA mode: {sta.ifconfig()[0]}')
network_init()

# 临时存储动作序列
action_sequence = []
def import_sequence(file_name='actions.json'):
    global action_sequence
    try:
        with open(file_name, 'r') as file:
            file_data = json.load(file)
            # 验证文件格式
            if 'actions' not in file_data:
                return False
            action_sequence = file_data['actions']
            return f"成功导入 {len(action_sequence)} 个动作序列"
    except OSError as e:
        return(f"无法打开文件: {e}")
#import_sequence()




def parse_multipart(data):#解析multipart/form-data格式数据
    try:
        # 第一步：查找文件名位置
        filename_start = data.index(b'filename="') + 10
        filename_end = data.index(b'"', filename_start)
        filename = data[filename_start:filename_end].decode('utf-8')
        
        # 第二步：定位文件内容起始位置
        header_end = data.index(b'\r\n\r\n') + 4
        
        # 第三步：查找内容结束边界
        footer_start = data.index(b'\r\n------', header_end)
        
        # 第四步：提取有效内容
        file_content = data[header_end:footer_start]
        
        return filename, file_content
    
    except (ValueError, IndexError):
        return None, None
def manual_unquote(s):#处理url编码
    result = []
    i = 0
    while i < len(s):
        if s[i] == '%' and i+2 < len(s):
            hex_part = s[i+1:i+3]
            if all(c in '0123456789ABCDEFabcdef' for c in hex_part):
                result.append(int(hex_part, 16))
                i += 3
                continue
        result.append(ord(s[i]))
        i += 1
    
    # 处理UTF-8多字节字符
    byte_array = bytes(result)
    try:
        return byte_array.decode('utf-8')
    except UnicodeDecodeError:
        return byte_array.decode('latin-1')







app = Microdot()


@app.route('/')
def index(request):
    return html, 200, {'Content-Type': 'text/html'}

@app.route('/upload', methods=['POST'])
def upload(request):
    #print(request.body)
    filename, file_content = parse_multipart(request.body)
    if filename:
        file_path = filename
        with open(file_path, 'wb') as f:
            f.write(file_content)  # 将文件内容写入服务器
        return Response('文件上传成功', status_code=200)
    else:
        return Response('没有找到文件', status_code=400)
@app.route('/upload_json', methods=['POST'])
def upload(request):
    #print(request.body)
    filename, file_content = parse_multipart(request.body)
    if filename:
        file_path = filename
        with open(file_path, 'wb') as f:
            f.write(file_content)  # 将文件内容写入服务器
            try:
                import_sequence(file_content)
                return Response('启动挂载成功', status_code=200)
            except:
                return Response('启动挂载失败', status_code=400)
    else:
        return Response('没有找到文件', status_code=400)

@app.route('/get_all_json')
def get_all_json(request):
    return os.listdir()
@app.route('/load_and_run_actions/<filename>')
def load_and_run_actions(request, filename):
    try:
        filename = manual_unquote(filename)
        import_sequence(filename)
        execute_all_actions()
        return Response('执行完毕', status_code=200)
    except:
        return Response('执行失败', status_code=400)
@app.route('/remove_action/<filename>')
def remove_action(request, filename):
    try:
        filename = manual_unquote(filename)
        os.remove(filename)
        return Response('删除成功', status_code=200)
    except:
        return Response('删除失败', status_code=400)


@app.route('/execute_all_actions')#执行所有动作
def execute_all_actions(request=None):
    for action in action_sequence:
        for servo in action['servos']:
            servo_controller.set_angle(servo['id'], servo['position'], action['delay'])
        time.sleep(action['delay']/1000)  # 延时防止舵机指令冲突
    return Response('执行完毕', 200)


if __name__ == '__main__':     
    app.run(debug=False, host='0.0.0.0', port=80)
